package cn.com.dashihui.api.service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;


import com.jfinal.aop.Duang;
import com.jfinal.json.FastJson;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.redis.Cache;
import com.jfinal.plugin.redis.Redis;

import cn.com.dashihui.api.Queue.OrderQueue;
import cn.com.dashihui.api.Queue.SingleQueue;
import cn.com.dashihui.api.base.BaseService;
import cn.com.dashihui.api.common.GroupCode;
import cn.com.dashihui.api.common.OrderCode;
import cn.com.dashihui.api.common.RedisKey;
import cn.com.dashihui.api.common.SysConfig;
import cn.com.dashihui.api.dao.Goods;
import cn.com.dashihui.api.dao.OrderG;
import cn.com.dashihui.api.dao.OrderPayAPIRecord;
import cn.com.dashihui.kit.CommonKit;
import cn.com.dashihui.kit.DatetimeKit;
import cn.com.dashihui.kit.DoubleKit;
import cn.com.dashihui.pay.wx.kit.HttpsRequest;
import cn.com.dashihui.pay.wx.kit.UtilKit;
import cn.com.dashihui.pay.wx.request.RefOrderReqData;
import cn.com.dashihui.pay.wx.response.RefOrderResData;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class GroupRedisService extends BaseService {
	
	
	private static ExecutorService executors = Executors.newFixedThreadPool(4);
	private static LinkedBlockingQueue<String> singleQueue = SingleQueue.getInstance();
	private Cache orderCache = Redis.use("OrderG");
	
	
	/**
	 * 把支付成功的订单加入缓存  异步执行团购业务逻辑
	 * @param order
	 */
	public void addQueue(OrderG order){
		String id = order.getInt("goodsid")+"";
		//根据  订单商品id  获取 Order队列
		Jedis jedis = orderCache.getJedis();
		jedis.watch(RedisKey.Key.QUEUE+id);
		OrderQueue orderQueue =  FastJson.getJson().parse(jedis.get(RedisKey.Key.QUEUE+id), OrderQueue.class);
		Transaction tx = jedis.multi();
		//保证  一个商品id 对应一个 OrderQueue
		if ( orderQueue == null ) {
			orderQueue = new OrderQueue();
		}
		//将订单加入 对应id的订单队列排号
		orderQueue.offer(order);
		tx.set(RedisKey.Key.QUEUE+id, JsonKit.toJson(orderQueue));
		List<Object> exec = tx.exec();
		if ( exec == null || exec.isEmpty() ) {
			//回滚
			jedis.resetState();
			jedis.unwatch();
			addQueue(order);
		}
		
		//通知异步执行
		singleQueue.offer(id);
		//开启线程池线程执行
		executors.submit(new OrderGDellService());
	}
	/**
	 * 处理  免单的团购订单 业务逻辑
	 * @return
	 */
	public OrderG dealGroupOrderG(OrderG order) {
		//1.判断是否有团中团号
		String teamNum = order.getStr("teamNum");
		int goodsid = order.getInt("goodsid");
		//查找商品信息
		Goods good = Goods.me().findById(goodsid);
		int teamSize = good.getInt("gbperson") - 1;
		
		if ( teamNum != null ){
			//处理团中团
			teamInTeam(order, teamNum, goodsid, good, teamSize);
		} 
		
		//1.2    处理完成团中团或者没有团中团   大团号%团队人数==0？
		int buyNum = order.getInt("buyNum");
		if(buyNum%(teamSize+1) == 0){
			//1.2.1  等于，
			//1 找出免单人数，
			int gbFree = good.getInt("gbfreeperson");
			System.out.println(">>>>>>>>>>>>>>>>>>>免单人数:"+gbFree);
			
			//查询数据库,查询出该商品未免单，订单状态未退款，的订单
			String sql = "SELECT * FROM t_bus_order_gb WHERE isFree=0 AND paystate=2 AND goodsid=? AND tuistate=0  ORDER BY buyNum ";
			List<OrderG> orderList = OrderG.me().find(sql, goodsid);
			if(orderList.size()>0&&orderList!=null){
				//需要免单的订单
				for(int i=0;i<gbFree;i++){
					orderFree(orderList.get(i),2);
				}
			}else{
				//查询失败 
				logger.error("查询团队异常---");
			}
		} 
		//1.2.1  不等于， 
		// 把该订单  放入缓存中去 <TeamNumber+goodsid, Map<Integer,OrderG>>   这里不做持久化  直接放入mysql    TODO 持久化需要
//		putTeam(order, goodsid);
		return null;
	}
	
	//  可省略   持久化需要  TODO
//	private void putTeam(OrderG order, int goodsid) {
//		Jedis jedis = orderCache.getJedis();
//		jedis.watch(RedisKey.Key.TEAMNUMBER+"_"+goodsid);
//		Map<Integer,OrderG> map = FastJson.getJson().parse(jedis.get(RedisKey.Key.TEAMNUMBER+"_"+goodsid), Map.class);
//		if ( map == null ) {
//			jedis.unwatch();
//			synchronized (GroupRedisService.class) {
//				if ( orderCache.get(RedisKey.Key.TEAMNUMBER+"_"+goodsid) == null ) {
//					map = new HashMap<Integer ,OrderG> ();
//					map.put(order.getInt("buyNum"), order);
//					orderCache.set( RedisKey.Key.TEAMNUMBER+"_"+goodsid , JsonKit.toJson(map));
//				}
//			}
//		} else {
//			Transaction tx = jedis.multi();
//			map.put(order.getInt("buyNum"), order);
//			tx.set( RedisKey.Key.TEAMNUMBER+"_"+goodsid , JsonKit.toJson(map));
//			List<Object> exec = tx.exec();
//			if( exec==null || exec.isEmpty() ){
//				jedis.resetState();
//				jedis.unwatch();
//				putTeam( order,  goodsid);
//			}
//		}
//		
//	}
	
	/**
	 * 处理团中团免单相关业务
	 * @param order
	 * @param teamNum
	 * @param goodsid
	 * @param good
	 * @param teamSize
	 */
	@SuppressWarnings("unchecked")
	private void teamInTeam(OrderG order, String teamNum, int goodsid, Goods good, int teamSize) {
		//1.1  有-》是团中团--》  查询团长是否已免单  团中团是否过期失效
		List<OrderG> teamOrders =null ;
		OrderG teamLeader = null ;
		
		Jedis jedis = orderCache.getJedis();
		jedis.watch( teamNum + "_" + goodsid );
		if ( order.getInt("isLeader") == GroupCode.isLeader.LEADER ) {
			teamOrders = new ArrayList<OrderG>();
			teamOrders.add(order);
			jedis.set( teamNum + "_" + goodsid , JsonKit.toJson(teamOrders));
			teamLeader = order;
		} else {
			teamOrders = FastJson.getJson().parse(jedis.get( teamNum + "_" + goodsid ),List.class);
			if ( teamOrders == null ) {
				//该团由于某种原因失效已经被删除
				// 把订单队列的订单号移除   查找下个 团中团加入
				findNewTeam(order, teamNum, goodsid, good, teamSize); 
			} else {
				//   去数据库取   团长订单
				int id = teamOrders.get(0).get("id");
				teamLeader = OrderG.me().findById(id);
//				持久化需要
//				Map<Integer,OrderG> maps = FastJson.getJson().parse(jedis.get( RedisKey.Key.TEAMNUMBER + "_" + goodsid ), Map.class) ;
//				teamLeader = maps.get(number);
			}
		}
		int isfree = teamLeader.getInt("isFree");
		int count = 1;
		if ( isfree == 0  ) {
			count = isLater(good, teamLeader);
			if( count!=1 ){
				teamLeader.set("isfree", GroupCode.isFree.LATE);
			}
		}
		Transaction tx = jedis.multi();
		if ( isfree == 0 && count == 1 ){
			//1.1.1 有效 --》 查团中团中 已支付数 与 成团人数 比较
			int payed = teamOrders.size();
			if ( ( payed < teamSize ) || ( payed == teamSize ) ) {
				//团长 送积分  把订单加进去 
				giveSppointByTeamNum(teamLeader);
				teamOrders.add(order);
				tx.set( teamNum + "_" + goodsid , JsonKit.toJson(teamOrders));
				List<Object> exec = tx.exec();
				if(exec == null || exec.isEmpty() ){
					//失败   有人改动
					jedis.resetState();
					jedis.unwatch();
					//重新执行
					teamInTeam(order, teamNum, goodsid, good,  teamSize);
				}
				if ( payed == teamSize ) {
					//1.1.1.1  相等 团长免单处理 
					//免单 TODO
					//找出团长，退款免单，                       送积分
					//免单
					orderFree(teamLeader,1);
				}
				//如果符合  把该团的团号设置为自己的
				order.set("teamNum", teamLeader.get("teamNum"));
				//1.1.1.2   执行大团免单 
			} else {
				// 1.1.1.3  大于 -》人数已满    
				// 删除这个  团中团缓存
				jedis.del( teamNum + "_" + goodsid );
				// 把订单队列的订单号移除   查找下个 团中团加入
				findNewTeam(order, teamNum, goodsid, good, teamSize); 
			}
			//  如果是  团长 有效开团  那么把 订单号 添加到  团中团队列
			if (  order.getInt("isLeader") == GroupCode.isLeader.LEADER  ) {
				createNewTeamList(teamNum, goodsid);
			}
			//1.1.2 无效 
		} else if ( count != 1  ){
			//1.1.2.1 订单超时   
			// 把订单队列的订单号移除   查找下个 团中团加入
			findNewTeam(order, teamNum, goodsid, good, teamSize);
		} else  {
			//1.1.2.2 大团把它免单了
			// 把订单队列的订单号移除   查找下个 团中团加入
			findNewTeam(order, teamNum, goodsid, good, teamSize);
		}
	}
	
	/**
	 * 免单
	 * @param certpath
	 * @param certpassword
	 * @param orderfree
	 */
	private void orderFree( OrderG orderfree ,int type ) {
		String certpath = PathKit.getRootClassPath()+"/"+PropKit.get("weixinpay.open.cert");
		String certpassword = PropKit.get("weixinpay.mch_id");
		orderfree.set("isFree", GroupCode.isFree.NEEDFREE);
		//退款
		if(orderfree.update()){
			//如果已更改为需免单，那么执行退款，并更改isFree状态以及记录t_bus_order_gb_log日志
			int paytype = orderfree.getInt("paytype");
			if(paytype==OrderCode.OrderPayMethod.BALANCE){
				//付款方式为余额的退款
				System.out.println(">>>>>>>>>>>付款方式为   余额   的退款<<<<<<<<<<<<<<");
			}else if(paytype==OrderCode.OrderPayMethod.WEIXIN){
				//付款方式为微信的退款
				System.out.println(">>>>>>>>>>>付款方式为   微信   的退款<<<<<<<<<<<<<<");
				//付款方式为微信的退款
				String orderNum = orderfree.getStr("orderNum");
				String out_refund_no = "TT"+DatetimeKit.getFormatDate("yyyyMMddHHmmssSSS")+CommonKit.randomNum(3);
				String total_fee = String.valueOf(Double.valueOf(DoubleKit.mul(orderfree.getDouble("amount"),100)).intValue()).toString();
				//向微信发起退款请求
				RefOrderReqData reOrderReqData = new RefOrderReqData(orderNum,out_refund_no,total_fee,total_fee, "免单退款");
				RefOrderResData reOrderRspData = null;
				try {
					reOrderRspData = (RefOrderResData)UtilKit.getObjectFromXML(new HttpsRequest(certpath,certpassword).post(PropKit.get("weixinpay.orderrefund"), reOrderReqData), RefOrderResData.class);
				}catch(Exception e){
					//发送退款请求失败
					Record re = new Record();
					re.set("orderNum", orderfree.getStr("orderNum"))
					  .set("refundNum",out_refund_no)
					  .set("type",GroupCode.exceptionType.GB_WX_SEND_REQ_FAILED)
					  .set("user",orderfree.getInt("userid"));
					  
					if ( type == 1 ) {
						re.set("action",GroupCode.exceptionType.GB_WX_SEND_REQ_FAILED_ACTION_TEAM)
						  .set("content",GroupCode.exceptionType.GB_WX_SEND_REQ_FAILED_CONTENT_TEAM);
					}  else {
						re.set("action",GroupCode.exceptionType.GB_WX_SEND_REQ_FAILED_ACTION)
						  .set("content",GroupCode.exceptionType.GB_WX_SEND_REQ_FAILED_CONTENT);
					}
					
					if(!Db.save("t_bus_order_exception_log", re)){
						if ( type == 1 ) {
							logger.error("微信团中团退款异常，订单号："+orderfree.getStr("orderNum"));
						} else {
							logger.error("微信退款异常，订单号："+orderfree.getStr("orderNum"));
						}
						
					}
				}
				//预支付完成
				if(reOrderRspData!=null){
					System.out.println("Response....:"+reOrderReqData);
					//保存接口请求记录
					String sendContent = UtilKit.getXMLFromObject(reOrderReqData);
					String returnContent = UtilKit.getXMLFromObject(reOrderRspData);
					new OrderPayAPIRecord().set("orderNum", orderNum)
						.set("sendContent", sendContent)
						.set("returnContent", returnContent)
						.set("payMethod", paytype)
						.set("flag", 4)
						.save();
					if(reOrderRspData.getReturn_code().equals("SUCCESS")&&reOrderRspData.getResult_code().equals("SUCCESS")){
						//更新订单免单退款状态为退款中。。。
						if(!orderfree.set("isFree", GroupCode.isFree.BACKING).update()){
							//更改订单为   退款中 状态失败 
							Record re = new Record();
							re.set("orderNum", orderfree.getStr("orderNum"))
							  .set("type",GroupCode.exceptionType.UPDATE_GB_REFUNDING_FAILED)
							  .set("user",orderfree.getInt("userid"));
							if ( type == 1 ) {
								 re.set("action",GroupCode.exceptionType.UPDATE_GBFREEPERSON_FAILED_ACTION_TEAM)
								  .set("content",GroupCode.exceptionType.UPDATE_GB_REFUNDING_FAILED_CONTENT_TEAM);
							}else {
								 re.set("action",GroupCode.exceptionType.UPDATE_GBFREEPERSON_FAILED_ACTION)
								  .set("content",GroupCode.exceptionType.UPDATE_GB_REFUNDING_FAILED_CONTENT);
							}
							 
							if(!Db.save("t_bus_order_exception_log", re)){
								if ( type == 1 ) {
									logger.error("需要 团中团 免单异常，订单号："+orderfree.getStr("orderNum"));
								}else {
									logger.error("需要免单异常，订单号："+orderfree.getStr("orderNum"));
								}
							}
						}
					}
				}
			}
		}else{
			//更改订单失败状态失败 
			Record re = new Record();
			re.set("orderNum", orderfree.getStr("orderNum"))
			  .set("type",GroupCode.exceptionType.UPDATE_GBFREEPERSON_FAILED)
			  .set("user",orderfree.getInt("userid"));
			if ( type == 1) {
				re.set("action",GroupCode.exceptionType.UPDATE_GBFREEPERSON_FAILED_ACTION_TEAM)
				  .set("content",GroupCode.exceptionType.UPDATE_GBFREEPERSON_FAILED_CONTENT_TEAM);
			} else {
				re.set("action",GroupCode.exceptionType.UPDATE_GBFREEPERSON_FAILED_ACTION)
				  .set("content",GroupCode.exceptionType.UPDATE_GBFREEPERSON_FAILED_CONTENT);
			}
			
			if(!Db.save("t_bus_order_exception_log", re)){
				if ( type == 1) {
					logger.error("团中团需要免单异常，订单号："+orderfree.getStr("orderNum"));
				} else {
					logger.error("   需要免单异常，订单号："+orderfree.getStr("orderNum"));
				}
				
			}
		}
	}
	/**
	 * 如果是团长开团，那么肯定是有效订单   那么需要在redis创建新的   团中团成员list集合
	 * @param teamNum
	 * @param goodsid
	 */
	private void createNewTeamList(String teamNum, int goodsid) {
		Jedis jedis = orderCache.getJedis();
		jedis.watch( RedisKey.Key.QUEUELIST + goodsid );
		List<String> teamList = FastJson.getJson().parse(jedis.get( RedisKey.Key.QUEUELIST + goodsid ), List.class);
		Transaction tx = jedis.multi();
		if ( teamList == null ) {
			teamList = new ArrayList<String>();
		} 
		teamList.add(teamNum);
		tx.set( RedisKey.Key.QUEUELIST + goodsid , JsonKit.toJson(teamList) );
		List<Object> exec = tx.exec();
		if( exec == null || exec.isEmpty() ){
			//失败  回滚
			jedis.resetState();
			jedis.unwatch();
			createNewTeamList( teamNum,  goodsid);
		}
	}
	/**
	 * 查询  最早的团中团订单   去执行加入
	 * @param order
	 * @param teamNum
	 * @param goodsid
	 * @param good
	 * @param teamSize
	 */
	private void findNewTeam(OrderG order, String teamNum, int goodsid, Goods good, int teamSize) {
		Jedis jedis = orderCache.getJedis();
		jedis.watch( RedisKey.Key.QUEUELIST + goodsid );
		List<String> teamList = FastJson.getJson().parse(jedis.get( RedisKey.Key.QUEUELIST + goodsid ), List.class);
		Transaction tx = jedis.multi();
		if ( teamList != null){
			teamList.remove(teamNum);
			// 查出下一个 未满团中团 团队执行加入
			tx.set( RedisKey.Key.QUEUELIST + goodsid , JsonKit.toJson(teamList) );
			List<Object> exec = tx.exec();
			if ( exec == null || exec.isEmpty() ) {
				//回滚
				jedis.resetState();
				jedis.unwatch();
				findNewTeam( order,  teamNum,  goodsid,  good,  teamSize);
			}
			//取出第一个 团中团号
			String teamNum1 = teamList.get(0);
			//判断团长是否符合  是否进行免单
			teamInTeam (order,teamNum1,goodsid,good,teamSize);
		}
	}
	
	
	/**
	 * 团中团是否 超过时间  
	 * @param good	商品
	 * @param teamLeader  团长订单
	 * @return  1  未超过  -1 超过 
	 */
	private int isLater(Goods good, OrderG teamLeader) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String time = format.format(teamLeader.getTimestamp("payDate"));
		String timelast = DatetimeKit.getIntervalFormatDate(good.getInt("gbLostTime")*60*60*1000, time);
		int count = DatetimeKit.compareDate(DatetimeKit.StrToDate(timelast));
		return count;
	} 
	
	
	/**
	 * 赠送邀请积分
	 * @param order
	 */
	public void giveSppointByTeamNum(OrderG order) {
		String sql = "SELECT tu.id,tu.sppoint FROM t_bus_order_gb tg "
				+ "LEFT JOIN t_bus_user tu ON tg.userid=tu.id "
				+ "WHERE tg.teamNum=? AND isLeader=? ";
		Record re = Db.findFirst(sql,order.getStr("teamNum"),GroupCode.isLeader.LEADER);
		if(re!=null){
			Double sppoint = re.getDouble("sppoint");
			//准备数据
			//奖励积分
			Double sppoints = 0.00;
			try {
				sppoints = SysConfig.getGroupSppoint();
			} catch (Exception e) {
				
			}
			Double newsppoint = DoubleKit.add(sppoint, sppoints);
			Db.update("UPDATE t_bus_user SET sppoint=? WHERE id=?",newsppoint,re.getInt("id"));
			
			Record record = new Record();
			record.set("type", 1)
				  .set("flag", 11)
				  .set("fromOrderNum", order.getStr("orderNum"))
				  .set("orderMoney", order.getDouble("amount"))
				  .set("userid", order.getInt("userid"))
				  .set("sppoint", sppoints)
				  .set("sppointHistory", sppoint)
				  .set("describe", "团购邀请赠送积分")
				  .set("createDate", new Date());
			Db.save("t_bus_user_value_log", record);	  
		}
	}
	
	
}
